﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TvDatabase;
using TvControl;
using VideoLan;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using TVServerComm;

namespace TVPlayer
{
    public partial class FormMain : Form
    {
        private TVServer server;
        private ChannelInfo currentChannel;
        private VideoLanClient videoLanClient;
        private VlcMediaPlayer vlcMediaPlayer;
        private Configuration config;
        private bool initialized = false;
        private ChangingChannelWindow loadingWindow;
        private bool connected;

        public FormMain()
        {
            InitializeComponent();
            
            config = Configuration.Load();

            if (!config.Initialized)
            {
                MessageBox.Show("Since this is the first time you start TV Player, you need to change some settings.");
                ConfigWindow wndConfig = new ConfigWindow();
                wndConfig.Config = new Configuration();
                if (wndConfig.ShowDialog() == DialogResult.OK)
                {
                    config = wndConfig.Config;
                    Configuration.Save(config);
                }
                else
                {
                    MessageBox.Show("The configuration must be done before the application can be used.");
                    this.Close();
                    Application.Exit();
                    return;
                }
            }

            loadingWindow = new ChangingChannelWindow();
            server = new TVServer();
            InitializeVLCComponent();

            labelProgramTime.Text = "";
            labelCurrentProgram.Text = "";
            labelNextProgram.Text = "";
            labelNextProgramTime.Text = "";
            textBoxProgramDescription.Text = "";

            toolStripButtonToggleSound.Image = imageListIcons.Images[0];

            if (!config.ShowInfoPanel && config.InformationPanelDisplayMode != InformationPanelDisplayModes.AlwaysShow)
                splitContainerHorisontal.Panel2Collapsed = true;

            if (!config.ShowEPGPanel)
                splitContainerVertical.Panel1Collapsed = true;

            if (config.ConnectOnStartup)
            {
                ConnectToTVServer();

                if (config.TuneLastChannelOnStartUp)
                    TuneChannel(config.LastChannel);
            }             
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            FormMain_Resize(null, null);  
        }

        private void InitializeVLCComponent()
        {
            if (initialized)
                return;

            try
            {
                videoLanClient = new VideoLanClient(config.VlcLocation);
                vlcMediaPlayer = videoLanClient.NewMediaPlayer(pictureBoxVideo.Handle);

                vlcMediaPlayer.PositionChanged += new EventHandler<PositionChangedEventArgs>(VlcPlayer_PositionChanged);
                vlcMediaPlayer.StateChanged += new EventHandler<StateChangedEventArgs>(VlcPlayer_StateChanged);
                initialized = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to load VLC component. Reason: " + ex.Message);
                initialized = false;
            }
        }

        private void ConnectToTVServer()
        {
            if (string.IsNullOrEmpty(config.MediaPortalServer))
            {
                MessageBox.Show("MediaPortal server must be set in configuration!");
                return;
            }

            InitializeVLCComponent();

            if (!server.Connect(config.MediaPortalServer))
            {
                MessageBox.Show("Failed to connect to server. Reason:\r\n: " + server.LastException.Message);
                return;
            }

            //Get tv groups
            toolStripComboBoxChannelGroups.Items.Clear();
            foreach (ChannelGroup group in server.GetGroupNames())
            {
                toolStripComboBoxChannelGroups.Items.Add(group.GroupName);
            }

            if (toolStripComboBoxChannelGroups.Items.Count > 0)
                toolStripComboBoxChannelGroups.SelectedIndex = 0;

            toolStripComboBoxChannelGroups.Enabled = true;
            toolStripComboBoxChannels.Enabled = true;

            connected = true;
            timerRefreshEPG.Start();
        }

        private void DisconnectFromTVServer()
        {
            timerRefreshEPG.Stop();
            server.Disconnect();
            connected = false;
            vlcMediaPlayer.Stop();            
        }


        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConnectToTVServer();
        }

        private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            DisconnectFromTVServer();
        }

        private void toolStripComboBoxChannelGroups_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Get tv channels
            toolStripComboBoxChannels.Items.Clear();
            foreach (ChannelInfo info in server.GetChannelInfosForGroup(toolStripComboBoxChannelGroups.SelectedItem.ToString()))
            {
                toolStripComboBoxChannels.Items.Add(info.name);
            }

            UpdateEPG();
        }

        private void toolStripComboBoxChannels_SelectedIndexChanged(object sender, EventArgs e)
        {
            TuneChannel(toolStripComboBoxChannels.SelectedItem.ToString());     
        }

        private void FormMain_Resize(object sender, EventArgs e)
        {
            if (vlcMediaPlayer.State == VlcState.Playing)
            {
             
            }
        }

        private void StartVLC(string streamUrl)
        {
            try
            {
                vlcMediaPlayer.Stop();
                VlcMedia media = videoLanClient.NewMedia( streamUrl);

                media.AddOption(":swscale-mode=2");
                media.AddOption(":video-filter=adjust:deinterlace:swscale");
                media.AddOption(":deinterlace-mode=" + config.VlcDeinterlace.ToLower());
                media.AddOption(":no-video-title-show");

                foreach (string option in config.VLCOptions)
                {
                    string formatOption = option;
                    if (formatOption.StartsWith("--"))
                        formatOption = formatOption.Substring(2);
                    if (!formatOption.StartsWith(":"))
                        formatOption = ":" + formatOption;
                    formatOption = formatOption.Trim();

                    media.AddOption(formatOption);
                }

                vlcMediaPlayer.Load(media);
                media.Dispose();
                vlcMediaPlayer.Play();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        private void VlcPlayer_PositionChanged(object sender, PositionChangedEventArgs e)
        {
       
        }
        private void VlcPlayer_StateChanged(object sender, StateChangedEventArgs e)
        {

            
        }

        private void showInformationPanelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            splitContainerHorisontal.Panel2Collapsed = !splitContainerHorisontal.Panel2Collapsed;
            showInformationPanelToolStripMenuItem.Checked = !splitContainerHorisontal.Panel2Collapsed;

            config.ShowInfoPanel = showInformationPanelToolStripMenuItem.Checked;
            Configuration.Save(config);
        }

        private void toolStripButtonConnect_Click(object sender, EventArgs e)
        {
            connectToolStripMenuItem_Click(null, null);
        }

        private void toolStripButtonOptions_Click(object sender, EventArgs e)
        {
            optionsToolStripMenuItem_Click(null, null);
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConfigWindow cfgWindow = new ConfigWindow();
            cfgWindow.Config = config;
            if (cfgWindow.ShowDialog() == DialogResult.OK)
            {
                Configuration.Save(cfgWindow.Config);
                config = cfgWindow.Config;
            }
        }

        private void toolStripButtonFullscreen_Click(object sender, EventArgs e)
        {
            vlcMediaPlayer.Video.FullScreen = true;
        }

        private void toolStripButtonToggleSound_Click(object sender, EventArgs e)
        {
            vlcMediaPlayer.Audio.ToggleMute();
            muteToolStripMenuItem.Checked = vlcMediaPlayer.Audio.Mute;
            toolStripButtonToggleSound.Image = imageListIcons.Images[vlcMediaPlayer.Audio.Mute ? 1 : 0];
        }

        private void backgroundWorkerChangeChannel_DoWork(object sender, DoWorkEventArgs e)
        {
            string streamUrl = string.Empty;
            TvResult result = server.StartTimeShifting(Int32.Parse(currentChannel.channelID), ref streamUrl);
            switch (result)
            {
                case TvResult.AllCardsBusy:
                    MessageBox.Show("There are no available cards.");
                    break;
                case TvResult.ChannelIsScrambled:
                    MessageBox.Show("Channel is scrambled.");
                    break;
                case TvResult.NoVideoAudioDetected:
                    MessageBox.Show("No audio/video detected.");
                    break;
                case TvResult.UnableToStartGraph:
                    MessageBox.Show("Unable to start graph.");
                    break;
                case TvResult.UnknownError:
                    MessageBox.Show("TV Server returned an unknown error.");
                    break;
                case TvResult.Succeeded:
                    StartVLC(streamUrl);
                    break;
            }

            string path = Path.Combine(Application.StartupPath, "Icons") + "\\" + currentChannel.name + ".png";
            if (!File.Exists(path))
            {
                path = Application.StartupPath + "\\nologo.png";
            }

            pictureBoxLogo.Image = Image.FromFile(GetChannelLogoPath(currentChannel.name));

            UpdateInformationPanel();
        }

        delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
        private void SetControlPropertyValue(Control oControl, string propName, object propValue)
        {
            if (oControl.InvokeRequired)
            {
                SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
                oControl.Invoke(d, new object[] { oControl, propName, propValue });
            }
            else
            {
                Type t = oControl.GetType();
                PropertyInfo[] props = t.GetProperties();
                foreach (PropertyInfo p in props)
                {
                    if (p.Name.ToUpper() == propName.ToUpper())
                    {
                        p.SetValue(oControl, propValue, null);
                    }
                }
            }
        }

        private void backgroundWorkerChangeChannel_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            loadingWindow.Close();
            loadingWindow = new ChangingChannelWindow();

            if (config.InformationPanelDisplayMode == InformationPanelDisplayModes.ShowOnchannelChange)
            {
                splitContainerHorisontal.Panel2Collapsed = false;
                timerInformationPanel.Start();
            }

            if (config.CloseEPGOnChannelChange)
            {
                splitContainerVertical.Panel1Collapsed = true;
            }

        }

        private void UpdateEPG()
        {
            List<ChannelInfo> channelInfo = server.GetChannelInfosForGroup(toolStripComboBoxChannelGroups.SelectedItem.ToString());
            listViewEPG.Items.Clear();
            foreach (ChannelInfo info in channelInfo)
            {
                //Update current channel info
                if (currentChannel != null && (info.channelID == currentChannel.channelID))
                    currentChannel = info;

                ListViewItem lvi = listViewEPG.Items.Add(info.name);
                lvi.SubItems.Add(info.epgNow.timeInfo);
                lvi.SubItems.Add(info.epgNow.title);
            }
        }

        private void listViewEPG_Resize(object sender, EventArgs e)
        {
            listViewEPG.Columns[0].Width = 100;
            listViewEPG.Columns[1].Width = 70;
            listViewEPG.Columns[2].Width = Math.Max(100, listViewEPG.Width - 170);
        }

        private void programGuideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            splitContainerVertical.Panel1Collapsed = !splitContainerVertical.Panel1Collapsed;
            programGuideToolStripMenuItem.Checked = !splitContainerVertical.Panel1Collapsed;

            config.ShowEPGPanel = programGuideToolStripMenuItem.Checked;
            Configuration.Save(config);
        }

        private void listViewEPG_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (listViewEPG.SelectedItems[0] == null)
                return;

            toolStripComboBoxChannels.SelectedItem = listViewEPG.SelectedItems[0].Text;
            //TuneChannel(listViewEPG.SelectedItems[0].Text);
        }

        private void TuneChannel(string channelName)
        {
   
            currentChannel = null;
            foreach (ChannelInfo info in server.GetChannelInfosForGroup(toolStripComboBoxChannelGroups.SelectedItem.ToString()))
            {
                if (info.name == channelName)
                {
                    currentChannel = info;
                    break;
                }
            }

            if (currentChannel == null)
            {
                return;
            }


            config.LastChannel = currentChannel.name;
            Configuration.Save(config);

            loadingWindow.LogoPath = GetChannelLogoPath(currentChannel.name);
            loadingWindow.ChannelName = currentChannel.name;
            loadingWindow.CurrentProgram = currentChannel.epgNow;
            loadingWindow.NextProgram = currentChannel.epgNext;
            loadingWindow.ActiveParentForm = this;
            loadingWindow.Show();

            backgroundWorkerChangeChannel.RunWorkerAsync(currentChannel);
        }

        private void timerInformationPanel_Tick(object sender, EventArgs e)
        {
            if (config.InformationPanelDisplayMode == InformationPanelDisplayModes.ShowOnchannelChange)
            {
                splitContainerHorisontal.Panel2Collapsed = true;
                timerInformationPanel.Stop();
            }
        }

        private void windowToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            showInformationPanelToolStripMenuItem.Checked = !splitContainerHorisontal.Panel2Collapsed;
            programGuideToolStripMenuItem.Checked = !splitContainerVertical.Panel1Collapsed;
            toolbarToolStripMenuItem.Checked = toolStripMain.Visible;
        }

        private void fileToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            connectToolStripMenuItem.Enabled = !connected;
            disconnectToolStripMenuItem.Enabled = connected;
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DisconnectFromTVServer();
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutWindow wndAbout = new AboutWindow();
            wndAbout.ShowDialog();
        }

        private void takeScreenshotToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveScreenshot();
        }

        private void timerRefreshEPG_Tick(object sender, EventArgs e)
        {
            if (!connected)
            {
                timerRefreshEPG.Stop();
                return;
            }

            UpdateEPG();
            UpdateInformationPanel();
        }

        private void UpdateInformationPanel()
        {
            if (currentChannel == null)
                return;

            SetControlPropertyValue(labelCurrentProgram, "Text", currentChannel.epgNow.title);
            SetControlPropertyValue(labelProgramTime, "Text", currentChannel.epgNow.timeInfo);
            SetControlPropertyValue(textBoxProgramDescription, "Text", currentChannel.epgNow.description);
            SetControlPropertyValue(labelNextProgram, "Text", currentChannel.epgNext.title);
            SetControlPropertyValue(labelNextProgramTime, "Text", currentChannel.epgNext.timeInfo);
            
        }

        private void toolbarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStripMain.Visible = !toolStripMain.Visible;
            toolbarToolStripMenuItem.Checked = toolStripMain.Visible;
        }

        private void fullscreenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToggleFullscreen();
        }

        private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            vlcMediaPlayer.Pause();
        }

        private void playToolStripMenuItem_Click(object sender, EventArgs e)
        {
            vlcMediaPlayer.Play();
        }

        private void muteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            vlcMediaPlayer.Audio.ToggleMute();
            muteToolStripMenuItem.Checked = vlcMediaPlayer.Audio.Mute;
            toolStripButtonToggleSound.Image = imageListIcons.Images[vlcMediaPlayer.Audio.Mute ? 1 : 0];
        }

        private void playbackToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            pauseToolStripMenuItem.Enabled = vlcMediaPlayer.State == VlcState.Playing;
            playToolStripMenuItem.Enabled = vlcMediaPlayer.State == VlcState.Paused;

            muteToolStripMenuItem.Checked = vlcMediaPlayer.Audio.Mute;            
        }

        private void helpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            HelpWindow wndHelp = new HelpWindow();
            wndHelp.Show();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            int currentIdx = 0;
            bool retValue = false;
            
            switch (keyData)
            {
                case Keys.PageDown:
                    currentIdx = toolStripComboBoxChannels.SelectedIndex;
                    if ((currentIdx + 1) < toolStripComboBoxChannels.Items.Count)
                        toolStripComboBoxChannels.SelectedIndex = (currentIdx + 1);
                    retValue =  true;
                    break;
                case Keys.PageUp:
                    currentIdx = toolStripComboBoxChannels.SelectedIndex;
                    if ((currentIdx - 1) >= 0)
                        toolStripComboBoxChannels.SelectedIndex = (currentIdx - 1);
                    retValue = true;
                    break;
                case Keys.F5:
                    SaveScreenshot();
                    retValue = true;
                    break;
                case Keys.F:
                    ToggleFullscreen();
                    retValue = true;
                    break;

            }
            return retValue;
        }

        private void SaveScreenshot()
        {
            if (vlcMediaPlayer.State != VlcState.Playing || vlcMediaPlayer.State == VlcState.Paused)
                return;

            string folder = Path.GetDirectoryName(Application.ExecutablePath) + "\\Snapshots\\";
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }

            string filename = folder + currentChannel.name + " " + currentChannel.epgNow.title + " " + DateTime.Now.ToString() + ".png";

            vlcMediaPlayer.Video.TakeSnapShot(filename, (uint)vlcMediaPlayer.Video.Width, (uint)vlcMediaPlayer.Video.Height);
            MessageBox.Show("Snapshot saved to " + filename);
        }

        private void ToggleFullscreen()
        {
            vlcMediaPlayer.Video.FullScreen = true;
        }

        private void homepageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("http://tvplayer.codeplex.com/");
        }

        private string GetChannelLogoPath(string channelName)
        {
            string path = Path.Combine(Application.StartupPath, "Icons") + "\\" + channelName + ".png";
            if (!File.Exists(path))
            {
                path = Application.StartupPath + "\\nologo.png";
            }

            return path;
        }
    }
}
